动态配置 WebSocket 端口
在开发中,将 WebSocket 的端口号硬编码在代码里是不好的实践。通过 .env 文件动态管理配置是标准做法:
# .env
WEBSOCKET_PORT=3031
WEBSOCKET_HOST=0.0.0.0
WEBSOCKET_PATH=/
WEBSOCKET_AUTO_PONG=true
WEBSOCKET_ALLOW_SICK_EVENTS=true
bash
// 读取环境变量
const port = parseInt(process.env.WEBSOCKET_PORT || '3031', 10)
typescript
修改 .env 中的端口号后,客户端也需要同步更新连接地址。
使用 dotenv 加载配置
import dotenv from 'dotenv'
dotenv.config()
const port = parseInt(process.env.WEBSOCKET_PORT || '3031', 10)
const host = process.env.WEBSOCKET_HOST || '0.0.0.0'
const autoPong = process.env.WEBSOCKET_AUTO_PONG === 'true'
typescript
环境变量的值都是字符串类型,需要手动转换为 number 或 boolean。这种手动转换容易出错,比如 parseInt(undefined) 会返回 NaN,'true' !== true。
使用 Joi 进行配置校验和类型转换
Joi 库可以同时解决两个问题:校验数据格式 + 自动类型转换。
pnpm install joi
bash
import Joi from 'joi'
const schema = Joi.object({
WEBSOCKET_PORT: Joi.number().default(3031),
WEBSOCKET_HOST: Joi.string().default('0.0.0.0'),
WEBSOCKET_PATH: Joi.string().default('/'),
WEBSOCKET_AUTO_PONG: Joi.boolean().default(true),
WEBSOCKET_ALLOW_SICK_EVENTS: Joi.boolean().default(true),
})
const { value, error } = schema.validate(process.env, {
allowUnknown: true, // 允许其他环境变量
stripUnknown: false,
})
if (error) {
throw new Error(`WebSocket 配置校验失败: ${error.message}`)
}
// value 中的值已经自动转换为了正确的类型
// WEBSOCKET_PORT 是 number, WEBSOCKET_AUTO_PONG 是 boolean
typescript
当 .env 文件中的配置格式有误时(比如端口写成了字符串 "abc"),Joi 会抛出明确的错误信息:"WEBSOCKET_PORT must be a number"。这个错误可以被 NestJS 的全局异常过滤器捕获,避免了运行时的隐晦报错。
将配置映射为 ws 库的 Options
校验后的值需要映射为 ws 库 WebSocket.Server 构造函数接受的 options 格式:
const wsOptions = {
port: value.WEBSOCKET_PORT,
host: value.WEBSOCKET_HOST,
path: value.WEBSOCKET_PATH,
autoPong: value.WEBSOCKET_AUTO_PONG,
allowSickEvents: value.WEBSOCKET_ALLOW_SICK_EVENTS,
}
const wss = new WebSocket.Server(wsOptions)
typescript
封装为工具函数
将配置读取、校验和映射逻辑封装为一个独立函数,在项目中复用:
// src/utils/get-ws-options.ts
import dotenv from 'dotenv'
import Joi from 'joi'
dotenv.config()
const schema = Joi.object({
WEBSOCKET_PORT: Joi.number().default(3031),
WEBSOCKET_HOST: Joi.string().default('0.0.0.0'),
WEBSOCKET_PATH: Joi.string().default('/'),
WEBSOCKET_AUTO_PONG: Joi.boolean().default(true),
WEBSOCKET_ALLOW_SICK_EVENTS: Joi.boolean().default(true),
})
export function getWsOptions() {
const { value, error } = schema.validate(process.env, {
allowUnknown: true,
})
if (error) {
throw new Error(`WebSocket 配置校验失败: ${error.message}`)
}
return {
port: value.WEBSOCKET_PORT,
host: value.WEBSOCKET_HOST,
path: value.WEBSOCKET_PATH,
autoPong: value.WEBSOCKET_AUTO_PONG,
allowSickEvents: value.WEBSOCKET_ALLOW_SICK_EVENTS,
}
}
typescript
// gateway 中使用
@WebSocketGateway(getWsOptions())
export class EventGateway {
// ...
}
typescript
这种配置管理模式在 NestJS 项目中非常通用——HTTP 端口、数据库连接、Redis 配置等都可以用同样的方式管理。Joi 提供的类型校验确保了运行时配置的正确性,比 TypeScript 的编译时类型检查多了一层运行时安全保障。
↑